package com.kaver.modular.dc.controller;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.kaver.core.base.controller.BaseController;
import com.kaver.core.base.tips.ErrorTip;
import com.kaver.core.common.annotion.Permission;
import com.kaver.core.common.constant.Const;
import com.kaver.core.common.constant.state.ChangeType;
import com.kaver.core.common.constant.state.ConfigStatus;
import com.kaver.core.log.LogObjectHolder;
import com.kaver.core.page.PageBT;
import com.kaver.core.page.PageInfoBT;
import com.kaver.core.shiro.ShiroKit;
import com.kaver.core.shiro.ShiroUser;
import com.kaver.core.support.CollectionKit;
import com.kaver.core.support.SafeProperties;
import com.kaver.modular.dc.service.IDcAppService;
import com.kaver.modular.dc.service.IDcConfigService;
import com.kaver.modular.dc.service.IDcConfigVersionService;
import com.kaver.modular.dc.service.IDcEnvService;
import com.kaver.modular.dc.service.IDcVersionService;
import com.kaver.modular.system.model.DcApp;
import com.kaver.modular.system.model.DcConfig;
import com.kaver.modular.system.model.DcConfigVersion;
import com.kaver.modular.system.model.DcEnv;
import com.kaver.modular.system.model.DcVersion;
import com.kaver.modular.system.transfer.ConfigVersionDto;

/**
 * 版本管理控制器
 *
 * @author Roc
 * @Date 2019-01-29 10:40:48
 */
@Controller
@RequestMapping("/dcConfigVersion")
public class DcConfigVersionController extends BaseController {

	private String PREFIX = "/dc/dcConfigVersion/";
	 @Autowired
	 private IDcAppService dcAppService;
	@Autowired
	private IDcConfigVersionService dcConfigVersionService;
	@Autowired
	private IDcVersionService dcVersionService;
	@Autowired
	private IDcConfigService dcConfigService;
	@Autowired
	DcConfigController dcConfigController;
	
	@Autowired
    private IDcEnvService dcEnvService;
	/**
	 * 跳转到版本管理首页
	 */
	@RequestMapping("")
	public String index() {
		return PREFIX + "dcConfigVersion.html";
	}

	/**
	 * 跳转到添加版本管理
	 */
	@RequestMapping("/dcConfigVersion_add")
	public String dcConfigVersionAdd() {
		return PREFIX + "dcConfigVersion_add.html";
	}

	/**
	 * 跳转到回滚
	 */
	@RequestMapping("/dcConfigVersion_rollback")
	public String dcConfigVersionRollback(Integer appId, Integer envId, Model model) {
		model.addAttribute("appId", appId);
		model.addAttribute("envId", envId);
		return PREFIX + "dcConfigVersion_rollback.html";
	}

	/**
	 * 跳转到修改版本管理
	 */
	@RequestMapping("/dcConfigVersion_update/{dcConfigVersionId}")
	public String dcConfigVersionUpdate(@PathVariable Integer dcConfigVersionId, Model model) {
		DcConfigVersion dcConfigVersion = dcConfigVersionService.selectById(dcConfigVersionId);
		model.addAttribute("item", dcConfigVersion);
		LogObjectHolder.me().set(dcConfigVersion);
		return PREFIX + "dcConfigVersion_edit.html";
	}

	/**
	 * 获取版本管理列表
	 */
	@RequestMapping(value = "/list")
	@ResponseBody
	public Object list(PageBT pageBT, Integer appId, Integer envId, Long version,String configKey) {
		DcConfigVersion entity = new DcConfigVersion();
		entity.setAppId(appId);
		entity.setEnvId(envId);
		if (version != null) {
		    entity.setVersion(version);
		}
		Wrapper<DcConfigVersion> wrapper = new EntityWrapper<>(entity);
		if (configKey != null) {
		    wrapper.like("config_key", configKey);
		}
		Page<DcConfigVersion> page = dcConfigVersionService
				.selectPage(new Page<>(pageBT.getPageNumber(), pageBT.getPageSize(), "version", false), wrapper);
		Page<ConfigVersionDto> page2 = new Page<>();
		BeanUtils.copyProperties(page, page2);
		page2.setRecords(null);
		List<ConfigVersionDto> dtos = new ArrayList<>();
		page2.setRecords(dtos);
		List<DcConfigVersion> prizes = page.getRecords();
		if (!CollectionKit.isEmpty(prizes)) {
			prizes.forEach(pz -> {
				ConfigVersionDto dto = new ConfigVersionDto();
				BeanUtils.copyProperties(pz, dto);
				if (dto.getSensitive() == 1 && !ShiroKit.hasPermission(Const.SENSITIVE_URL)) {
					dto.setConfigValue("******");
				}
				dto.setChangeTypeDesc(ChangeType.valueOf(dto.getChangeType()));
				dtos.add(dto);
			});
		}
		return new PageInfoBT<>(page2);
	}
	/**
     * 下载配置
     */
	@Permission
    @RequestMapping(value = "/download")
    @ResponseBody
    public void download(Integer appId,Integer envId,Long version,HttpServletResponse response) {
    	DcConfigVersion entity = new DcConfigVersion();
    	entity.setAppId(appId);
    	entity.setEnvId(envId);
    	entity.setVersion(version);
    	Wrapper<DcConfigVersion> wrapper = new EntityWrapper<DcConfigVersion>(entity);
    	List<DcConfigVersion> configs = dcConfigVersionService.selectList(wrapper);
    	SafeProperties properties = new SafeProperties();
		for (DcConfigVersion node : configs) {
			if (node.getSensitive() == 1 && !ShiroKit.hasPermission(Const.SENSITIVE_URL)) {
				node.setConfigValue("******");
			}
			properties.setProperty(node.getConfigKey(), node.getConfigValue(),node.getConfigDesc());
		}
		DcApp app = dcAppService.selectById(appId);
		response.setContentType("application/force-download");
		response.addHeader("Content-Disposition", "attachment;fileName=" + app.getAppName() + ".properties");
		try {
			properties.store(response.getOutputStream());
		} catch (IOException e) {
		}
    }
//	/**
//	 * 新增版本管理
//	 */
//	@RequestMapping(value = "/add")
//	@ResponseBody
//	public Object add(DcConfigVersion dcConfigVersion) {
//		dcConfigVersionService.insert(dcConfigVersion);
//		return SUCCESS_TIP;
//	}

//	/**
//	 * 删除版本管理
//	 */
//	@RequestMapping(value = "/delete")
//	@ResponseBody
//	public Object delete(@RequestParam Integer dcConfigVersionId) {
//		dcConfigVersionService.deleteById(dcConfigVersionId);
//		return SUCCESS_TIP;
//	}

//	/**
//	 * 修改版本管理
//	 */
//	@RequestMapping(value = "/update")
//	@ResponseBody
//	public Object update(DcConfigVersion dcConfigVersion) {
//		dcConfigVersionService.updateById(dcConfigVersion);
//		return SUCCESS_TIP;
//	}

	/**
	 * 版本管理详情
	 */
	@RequestMapping(value = "/detail/{dcConfigVersionId}")
	@ResponseBody
	public Object detail(@PathVariable("dcConfigVersionId") Integer dcConfigVersionId) {
		return dcConfigVersionService.selectById(dcConfigVersionId);
	}

	/**
	 * 版本回滚
	 */
	@Permission
	@RequestMapping(value = "/rollback")
	@ResponseBody
	@Transactional
	public Object rollback(Integer appId, Integer envId, Long version) {
		ShiroUser user = ShiroKit.getUser();
		DcConfigVersion entity = new DcConfigVersion();
		entity.setAppId(appId);
		entity.setEnvId(envId);
		entity.setVersion(version);
		Wrapper<DcConfigVersion> wrapper = new EntityWrapper<DcConfigVersion>(entity);
		wrapper.ne("change_type", ChangeType.DEL.getCode());
		wrapper.isNull("parent_id");
		List<DcConfigVersion> configVersions = dcConfigVersionService.selectList(wrapper);
//		if (CollectionUtils.isEmpty(configVersions)) {
//			return new ErrorTip(500, "版本数据不存在");
//		}
		Map<String, DcConfigVersion> map = new HashMap<>();
		configVersions.forEach(action -> {
			map.put(action.getConfigKey(), action);
		});
		Long maxVersion = dcConfigVersionService.maxVersion(appId, envId);
		if (maxVersion == null) {
			return new ErrorTip(500, "版本数据不存在");
		}
		if (version.equals(maxVersion)) {
			return new ErrorTip(500, "回滚版本号不能和当前版本号相同");
		}
		if (version > maxVersion) {
			return new ErrorTip(500, "回滚版本号不存在");
		}
		entity.setVersion(maxVersion);

		List<DcConfigVersion> list = dcConfigVersionService.selectList(wrapper);
		List<DcConfigVersion> newversion = new ArrayList<>();
		DcVersion dcver = new DcVersion();
		dcver.setCreateTime(new Date());
		dcVersionService.insert(dcver);
		Map<String, DcConfigVersion> map2 = new HashMap<>();
		list.forEach(dcversion -> {
			DcConfigVersion configVersion = new DcConfigVersion();
			DcConfigVersion dcConfigVersion = map.get(dcversion.getConfigKey());
			if (dcConfigVersion != null) {
				BeanUtils.copyProperties(dcConfigVersion, configVersion);
				if (!eq(dcversion, dcConfigVersion)) {
					configVersion.setChangeType(ChangeType.UPDATE.getCode());
				} else {
					configVersion.setChangeType(ChangeType.OLD.getCode());
				}
			} else {
				BeanUtils.copyProperties(dcversion, configVersion);
				configVersion.setChangeType(ChangeType.DEL.getCode());
			}
			map2.put(configVersion.getConfigKey(), configVersion);
			configVersion.setId(null);
			configVersion.setVersion(dcver.getId());
			configVersion.setCreateTime(new Date());
			configVersion.setCreateUser(user.getName());
			newversion.add(configVersion);
		});
		configVersions.forEach(action -> {
			if (!map2.containsKey(action.getConfigKey())) {
				DcConfigVersion configVersion = new DcConfigVersion();
				BeanUtils.copyProperties(action, configVersion);
				configVersion.setChangeType(ChangeType.ADD.getCode());
				configVersion.setId(null);
				configVersion.setVersion(dcver.getId());
				configVersion.setCreateTime(new Date());
				configVersion.setCreateUser(user.getName());
				newversion.add(configVersion);
			}
		});
		if (!newversion.isEmpty()) {
			dcConfigVersionService.insertBatch(newversion);
		}
		DcConfig config = new DcConfig();
		config.setAppId(appId);
		config.setEnvId(envId);
		Wrapper<DcConfig> wrapper2 = new EntityWrapper<>(config);
		dcConfigService.delete(wrapper2);
		List<DcConfig> configs = new ArrayList<>();
		newversion.forEach(action->{
			if (!ChangeType.DEL.getCode().equals(action.getChangeType())) {
				DcConfig dcConfig = new DcConfig();
				BeanUtils.copyProperties(action ,dcConfig);
				dcConfig.setId(null);
				dcConfig.setCreateTime(new Date());
				dcConfig.setCreateUser(user.getName());
				dcConfig.setStatus(ConfigStatus.PUB.getCode());
				configs.add(dcConfig);
			}
		});
		if (!configs.isEmpty()) {
			dcConfigService.insertBatch(configs);
		}
		// 如果次项目存在子项目 需要发布子项目
		dcConfigController.pubSubApp(appId, envId, newversion,user);
		DcEnv env = dcEnvService.selectById(envId);
        DcApp app = dcAppService.selectById(appId);
        dcConfigController.clearCache(app.getAppName(), env.getEnvName());
		return SUCCESS_TIP;
	}

	private boolean eq(DcConfigVersion version1, DcConfigVersion version2) {
		if (version1.getAppId().equals(version2.getAppId()) && version1.getEnvId().equals(version2.getEnvId())
				&& version1.getConfigKey().equals(version2.getConfigKey())
				&& version1.getConfigValue().equals(version2.getConfigValue())
				&& version1.getConfigDesc().equals(version2.getConfigDesc())) {
			return true;
		}
		return false;
	}
}
